//
// Created by wll on 2021/9/8.
//

#ifndef XYZ_COMPILERID_H
#define XYZ_COMPILERID_H

#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <cstring>
#include "sha1.h"
#include "IoUtil.h"
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem.hpp>

struct CompilerId
{
    std::string compiler_id;
    std::string grammar_file_name;
    std::string parent_compiler_id;
    time_t grammar_file_modify_time;

    const CompilerId& operator= (const CompilerId& that)
    {
        this->compiler_id = that.compiler_id;
        this->grammar_file_name = that.grammar_file_name;
        this->parent_compiler_id = that.parent_compiler_id;
        this->grammar_file_modify_time = that.grammar_file_modify_time;

        return *this;
    }

    std::string ToString()
    {
        std::stringstream ss;
        ss  << "(compiler_id=" << compiler_id
            << ", grammar_file_name=" << grammar_file_name
            << ", parent_compiler_id=" << parent_compiler_id << ")";
        return ss.str();
    }

    void Save(std::ostream &o) const
    {
        ::Save(o, this->parent_compiler_id);
        ::Save(o, this->compiler_id);
        ::Save(o, this->grammar_file_name);
        o.write(reinterpret_cast<const char *>(&grammar_file_modify_time), sizeof(grammar_file_modify_time));
    }

    void Load(std::istream& i)
    {
        ::Load(i, this->parent_compiler_id);
        ::Load(i, this->compiler_id);
        ::Load(i, this->grammar_file_name);
        i.read(reinterpret_cast<char *>(&grammar_file_modify_time), sizeof(grammar_file_modify_time));
    }
};

inline time_t GetLastModifyTime(std::string grammar_file_name)
{
    return boost::filesystem::detail::last_write_time(grammar_file_name.c_str());
}

inline std::string FileContentHash(std::string grammar_file_name)
{
    string result;
    return (sha1(grammar_file_name, result) ? result : "");
}

inline std::string NoDirFileName(std::string file_name)
{
    size_t pos = file_name.rfind('/');
    return (pos==std::string::npos ? file_name : file_name.substr(pos+1));
}

inline std::string CaculateCompilerId(std::string grammar_file_name)
{
    return NoDirFileName(grammar_file_name) + "#" + FileContentHash(grammar_file_name);
}

#endif //XYZ_COMPILERID_H
